package cn.easyplatform.studio.utils;

import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.vos.MediaFileVo;
import com.alibaba.fastjson.JSON;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import java.io.*;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;

import static java.nio.charset.StandardCharsets.UTF_8;

public class FileUtil {
    private final static Logger log = LoggerFactory.getLogger(FileUtil.class);

    public static String getStreamWithFile(String path) throws Exception {
        InputStream inputStream = null;
        String result = null;
        inputStream = new FileInputStream(new File(path));
        result = IOUtils.toString(inputStream, UTF_8);
        return result;
    }

    public static boolean setBytesWithFile(byte[] bytes, String filePath) {
        InputStream in = new ByteArrayInputStream(bytes);
        boolean ret_bl = false;
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(filePath, false);
            byte[] b = new byte[1024];
            int length = 0;
            while ((length = in.read(b)) > 0) {
                os.write(b, 0, length);
            }
            os.close();
            in.close();
            ret_bl = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (in != null) {
                    in.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret_bl;
    }

    public static boolean setStreamWithFile(String content, String filePath) {
        return FileUtil.setBytesWithFile(content.getBytes(), filePath);
    }

    public String getRootPath() {
        //从classpath根开始查找
        String path = this.getClass().getClassLoader().getResource("/").getPath();
        //String temp = path.replaceFirst("file:/", "").replaceFirst("WEB-INF/classes/", "");
        //文件分隔符（在 UNIX 系统中是“/”）
        String separator = System.getProperty("file.separator");
        if ("/".equals(separator)) {
            return path;
        } else {
            return path.substring(1);
        }
    }

    public static String getCachePath() {
        String mainDir = StudioApp.getServletContext().getRealPath("/cache/");
        FileUtil.createPath(mainDir);
        return "/cache/";
    }

    public static void createPath(String fileStr) {
        String mainDir = StudioApp.getServletContext().getRealPath("/cache/");
        File destDir = new File(fileStr);
        if (!destDir.exists()) {
            try {
                FileUtils.forceMkdir(destDir);//在根创建了文件夹
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void copyFileUsingFileChannels(File source, File dest) throws IOException {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(source);
            output = new FileOutputStream(dest);
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }
        } finally {
            input.close();
            output.close();
        }
    }

    public static void copyDir(String sourcePath, String newPath) throws IOException {
        File file = new File(sourcePath);
        String[] filePath = file.list();

        if (!(new File(newPath)).exists()) {
            (new File(newPath)).mkdir();
        }

        for (int i = 0; i < filePath.length; i++) {
            if ((new File(sourcePath + file.separator + filePath[i])).isDirectory()) {
                copyDir(sourcePath + file.separator + filePath[i], newPath + file.separator + filePath[i]);
            }

            if (new File(sourcePath + file.separator + filePath[i]).isFile()) {
                copyFileUsingFileChannels(new File(sourcePath + file.separator + filePath[i]), new File(newPath + file.separator + filePath[i]));
            }

        }
    }

    public static void copyDirInFile(String sourcePath, String newPath) throws IOException {
        File file = new File(sourcePath);
        String[] filePath = file.list();

        if (!(new File(newPath)).exists()) {
            (new File(newPath)).mkdir();
        }

        for (int i = 0; i < filePath.length; i++) {
            if (new File(sourcePath + file.separator + filePath[i]).isFile()) {
                copyFileUsingFileChannels(new File(sourcePath + file.separator + filePath[i]), new File(newPath + file.separator + filePath[i]));
            }
        }
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     *
     * @param dir 将要删除的文件目录
     * @return boolean Returns "true" if all deletions were successful.
     * If a deletion fails, the method stops attempting to
     * delete and returns "false".
     */
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }

    public static void mkdirForNoExists(String dirPath) {
        if (!new File(dirPath).exists()) {
            try {
                FileUtils.forceMkdir(new File(dirPath));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static List<MediaFileVo> getAllFileInDir(String dirPath, String type) {
        List<MediaFileVo> mediaFileVos = new ArrayList<>();
        File dir = new File(dirPath);
        if (dir.isDirectory()) {
            String[] fileName = dir.list();
            List<String> pathName = new ArrayList<>();
            for (String name : fileName) {
                pathName.add(dirPath + File.separator + name);
            }
            for (int i = 0; i < pathName.size(); i++) {
                MediaFileVo vo = new MediaFileVo();
                File pathFile = new File(pathName.get(i));
                vo.setName(fileName[i]);
                vo.setPath(pathName.get(i));
                DecimalFormat df = new DecimalFormat("#.##KB");
                double size = pathFile.length() / 1024.0;
                vo.setSize(df.format(size));
                vo.setType(type);
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String dateString = format.format(pathFile.lastModified());
                try {
                    vo.setUpdateDate(format.parse(dateString));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                mediaFileVos.add(vo);
            }
        }
        return mediaFileVos;
    }


    /**
     * 判断字符串中是否包含中文
     *
     * @param str 待校验字符串
     * @return 是否为中文
     * @warn 不能校验是否为中文标点符号
     */
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    /**
     * 获取文件类型
     *
     * @param pathStr 路径名
     * @return
     */
    public static String getFileContentType(String pathStr) {
        String mimeStr = null;
        try {
            File f = new File(pathStr);
            FileInputStream is = new FileInputStream(f);
            ContentHandler contenthandler = new BodyContentHandler();
            Metadata metadata = new Metadata();
            metadata.set(Metadata.RESOURCE_NAME_KEY, f.getName());
            Parser parser = new AutoDetectParser();
            //OOXMLParser parser = new OOXMLParser();
            ParseContext parseContext = new ParseContext();
            parser.parse(is, contenthandler, metadata, parseContext);
            mimeStr = metadata.get(Metadata.CONTENT_TYPE);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TikaException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mimeStr;
    }

    /**
     * 获得指定文件的byte数组
     * @param filePath 路径
     * @return
     */
    public static byte[] getBytes(String filePath){
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * @功能  精确计算base64字符串文件大小（单位：B）
     * @注意  base64字符串(不含data:audio/wav;base64,文件头)
     */
    public static double base64fileSize(String base64String)  {
        //1.获取base64字符串长度(不含data:audio/wav;base64,文件头)
        base64String = base64String.replaceAll("\n", "");
        int size0 = base64String.length();
        //2.获取字符串的尾巴的最后10个字符，用于判断尾巴是否有等号，正常生成的base64文件'等号'不会超过4个
        String tail = base64String.substring(size0-10);
        //3.找到等号，把等号也去掉,(等号其实是空的意思,不能算在文件大小里面)
        int equalIndex = tail.indexOf("=");
        if(equalIndex > 0) {
            size0 = size0 - (10 - equalIndex);
        }
        //4.计算后得到的文件流大小，单位为字节
        return size0 - ((double)size0 / 8 ) * 2;
    }

    //删除文件夹
    //param folderPath 文件夹完整绝对路径

    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); //删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            java.io.File myFilePath = new java.io.File(filePath);
            myFilePath.delete(); //删除空文件夹
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //删除指定文件夹下所有文件
    //param path 文件夹完整绝对路径
    public static boolean delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
                delFolder(path + "/" + tempList[i]);//再删除空文件夹
                flag = true;
            }
        }
        return flag;
    }

    public static Properties getJarMFWithFileName(String realFilePath) {
        try {
            JarFile jarFile = new JarFile(realFilePath);
            JarEntry entry = jarFile.getJarEntry("META-INF/MANIFEST.MF");
            if (entry != null) {
                Properties prop = new Properties();
                prop.load(new InputStreamReader(jarFile.getInputStream(entry),"utf-8"));
                return prop;
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static InputStream getJarImageWithFileName(String realFilePath, String imageFilePath) {
        try {
            JarFile jarFile = new JarFile(realFilePath);
            JarEntry entry = jarFile.getJarEntry(imageFilePath);
            if (entry != null) {
                return jarFile.getInputStream(entry);
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void unJar(File src, File desDir) throws FileNotFoundException, IOException {
        JarInputStream jarIn = new JarInputStream(new BufferedInputStream(new FileInputStream(src)));
        byte[] bytes = new byte[1024];

        while (true) {
            ZipEntry entry = jarIn.getNextJarEntry();
            if (entry == null) break;

            File desTemp = desDir.getAbsoluteFile();

            if (entry.isDirectory()) {//jar条目是空目录
                if (!desTemp.exists()) desTemp.mkdirs();
                System.out.println("MakeDir: " + entry.getName());
            } else {//jar条目是文件
                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(desTemp));
                int len = jarIn.read(bytes, 0, bytes.length);
                while (len != -1) {
                    out.write(bytes, 0, len);
                    len = jarIn.read(bytes, 0, bytes.length);
                }

                out.flush();
                out.close();
                System.out.println("Copyed: " + entry.getName());
            }
            jarIn.closeEntry();
        }

        //关闭JarInputStream
        jarIn.close();
    }

    public static List<String> getFilePathWithDirectory(String path) {
        List<String> files = new ArrayList<>();
        File file = new File(path);
        if (file.isDirectory() == false)
            return files;
        for (String filePath : file.list()) {
            if (new File(filePath).isDirectory() == false && filePath.equals(".DS_Store") == false && !filePath.equals("restore"))
                files.add(filePath);
        }
        return files;
    }

    public static String getStringWithStream(InputStream input) throws IOException {
        StringBuffer out = new StringBuffer();
        byte[] b = new byte[4096];
        for (int n; (n = input.read(b)) != -1;) {
            out.append(new String(b, 0, n));
        }
        return out.toString();
    }

    public String getAllRole() {
        Pattern r = Pattern.compile(" value=\"([a-zA-z0-9_]*)\"");
        InputStream inputStream = getClass().getResourceAsStream("/web/include/editor/workbench/role.zul");
        String jsonResult = null;
        try {
            jsonResult = FileUtil.getStringWithStream(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.error(jsonResult);
        if (jsonResult == null)
            return null;
        // 现在创建 matcher 对象
        Matcher m = r.matcher(jsonResult);
        HashMap<String,Integer> map = new HashMap<>();
        while(m.find()){
            map.put(m.group(1), 1);
        }
        System.out.println("size: " + map.keySet().size());
        String s = JSON.toJSONString(map);
        System.out.println("s: " + s);
        return s;
    }
}
